package com.mate.cloud.auth.utils;

import cn.hutool.core.util.StrUtil;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * JWT工具类的加密算法就普普通通的HS256
 *
 * @author: MI
 * @email: 448341911@qq.com
 * @createTime: 2025/6/6 14:31
 * @updateUser: MI
 * @updateTime: 2025/6/6 14:31
 * @updateRemark: 修改内容
 * @version: 1.0
 */
@Slf4j
public class JwtUtil {

    //常量
    public static final long EXPIRE = 1000 * 60 * 60 * 4; //token过期时间,4个小时
    public static final String APP_SECRET = "774f1d7e-a572-414c-a675-f0efee9c4bb1"; //秘钥

    // 安全密钥（实际项目中应从安全配置中获取）
    private static final String SECRET_KEY = "mySecretKeyMustBeAtLeast32BytesLong123456";
    // 过期时间（分钟）
    private static final long EXPIRATION_MINUTES = 30;


    /**
     * 生成JWT Token
     *
     * @param subject 主题（如用户名）
     * @return JWT Token字符串
     */
    public static String generateToken(String subject) {
        // 生成安全密钥
        SecretKey key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes());

        // 计算过期时间
        Date now = new Date();
        Date expiration = new Date(now.getTime() + TimeUnit.MINUTES.toMillis(EXPIRATION_MINUTES));

        // 构建JWT
        return Jwts.builder()
                .subject(subject)                      // 设置主题
                .issuedAt(now)                         // 签发时间
                .expiration(expiration)                // 过期时间
                .signWith(key)                         // 签名密钥
                .compact();                            // 生成字符串
    }

    /**
     * 解析Token获取声明(Claims)
     *
     * @param token JWT Token
     * @return 声明对象
     */
    public static Claims parseToken(String token) {
        SecretKey key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes());

        JwtParser parser = Jwts.parser()
                .verifyWith(key)  // 设置验证密钥
                .build();

        return parser.parseSignedClaims(token).getPayload();
    }


    /**
     * 验证Token是否有效（包括过期检查）
     *
     * @param token JWT Token
     * @return 是否有效
     */
    public static boolean validateToken(String token) {
        try {
            SecretKey key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes());

            Jwts.parser()
                    .verifyWith(key)
                    .build()
                    .parseSignedClaims(token);

            return true;  // 验证通过
        } catch (ExpiredJwtException ex) {
            System.out.println("Token已过期: " + ex.getMessage());
            return false;
        } catch (Exception ex) {
            System.out.println("无效Token: " + ex.getMessage());
            return false;
        }
    }

    /**
     * 从Token中获取主题（如用户名）
     *
     * @param token JWT Token
     * @return 主题内容
     */
    public static String getSubjectFromToken(String token) {
        return parseToken(token).getSubject();
    }

    /**
     * 生成jwt
     * 使用Hs256算法, 私匙使用固定秘钥
     *
     * @param secretKey jwt秘钥
     * @param ttlMillis jwt过期时间(毫秒)
     * @param claims    设置的信息
     * @return
     */
    public static String createJwt(String secretKey, long ttlMillis, Map<String, Object> claims) {
        // 指定签名的时候使用的签名算法，也就是header那部分
//        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        if (StrUtil.isEmpty(secretKey)) {
            secretKey = APP_SECRET;
        }
        // 生成JWT的时间
        long expMillis = System.currentTimeMillis() + ttlMillis;
        Date exp = new Date(expMillis);

        //生成 HMAC 密钥，根据提供的字节数组长度选择适当的 HMAC 算法，并返回相应的 SecretKey 对象。
        SecretKey key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8));

        // 设置jwt的body
        JwtBuilder builder = Jwts.builder()
                // 设置签名使用的签名算法和签名使用的秘钥
                .signWith(key)
                // 如果有私有声明，一定要先设置这个自己创建的私有的声明，这个是给builder的claim赋值，一旦写在标准的声明赋值之后，就是覆盖了那些标准的声明的
                .claims(claims)
                // 设置过期时间
                .expiration(exp);
        return builder.compact();
    }

    /**
     * Token解密
     *
     * @param secretKey jwt秘钥 此秘钥一定要保留好在服务端, 不能暴露出去, 否则sign就可以被伪造, 如果对接多个客户端建议改造成多个
     * @param token     加密后的token
     * @return
     */
    public static Claims parseJWT(String token) {
        return parseJWT(null, token);
    }

    /**
     * Token解密
     *
     * @param secretKey jwt秘钥 此秘钥一定要保留好在服务端, 不能暴露出去, 否则sign就可以被伪造, 如果对接多个客户端建议改造成多个
     * @param token     加密后的token
     * @return
     */
    public static Claims parseJWT(String secretKey, String token) {
        if (StrUtil.isEmpty(secretKey)) {
            secretKey = APP_SECRET;
        }
        //生成 HMAC 密钥，根据提供的字节数组长度选择适当的 HMAC 算法，并返回相应的 SecretKey 对象。
        SecretKey key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8));

        // 得到DefaultJwtParser
        JwtParser jwtParser = Jwts.parser()
                // 设置签名的秘钥
                .verifyWith(key)
                .build();
        Jws<Claims> jws = jwtParser.parseSignedClaims(token);
        Claims claims = jws.getPayload();
        return claims;
    }


}
